﻿using System;
using System.Diagnostics;
using MBWebService;
using MBWebService.Core;
using System.Threading;
using MediaBrowser.Library;
using System.Security.AccessControl;
using System.Security.Principal;
using MediaBrowser;
using System.ServiceModel;
using MBWebService.Core.Logging;
using MBWebService.Core.Client;
using MBWebService.Server.Proxy;
using MBWebService.Core.Classes;
using MBWebService.Service;

namespace PluginLoader
{
    class Program
    {
        #region Private members

        private static bool loading = false;
        static Mutex _mutex;
        static bool _hasHandle;
        static ServiceConfigData _config;

        #endregion

        static void Main(string[] args)
        {
            AppSettings.Initialise();

            // TestKernel();
            InstallClient();
            // UninstallClient();
            // StartService();
            // UpdateServiceProxy();

            //AttachToService("Service1");
            //AttachToService("Service2");
            
            while (Console.ReadKey().Key != ConsoleKey.Enter) { };
        }

        private static void StartService()
        {
            Console.WriteLine("Starting service");
            Console.Write("Loading.");
            loading = true;
            ThreadPool.QueueUserWorkItem((o) =>
            {
                while (loading)
                {
                    Console.Write(".");
                    Thread.Sleep(TimeSpan.FromSeconds(1));
                }
            }
            );
            var success = LoadService();

            loading = false;
            Console.WriteLine(string.Empty);
            if (success)
            {
                Console.WriteLine("Service started");

                Console.WriteLine("[Press Enter to stop service]");
            }
            else
            {
                Console.WriteLine("Failure starting service");
                Console.WriteLine("[Press Enter to close]");
            }
        }

        private static void TestKernel()
        {
            Kernel.Init(KernelLoadDirective.LoadServicePlugins);
            var bob = Kernel.Instance.ItemRepository.RetrieveItem(new Guid("7ce7c613-5ca5-30e3-24d0-b221e43460ef"));
            var bob2 = Kernel.Instance.ItemRepository.RetrieveChildren(new Guid("7ce7c613-5ca5-30e3-24d0-b221e43460ef"));
        }

        private static bool LoadService()
        {
            bool retval = false;

            _mutex = new Mutex(false, Kernel.MBSERVICE_MUTEX_ID);
            {
                //set up so everyone can access
                var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
                var securitySettings = new MutexSecurity();
                try
                {
                    //don't bomb if this fails
                    securitySettings.AddAccessRule(allowEveryoneRule);
                    _mutex.SetAccessControl(securitySettings);
                }
                catch (Exception)
                {
                    //just log the exception and go on
                    //Logger.ReportException("Failed setting access rule for mutex.", e);
                }
                try
                {
                    try
                    {
                        _hasHandle = _mutex.WaitOne(5000, false);
                        if (_hasHandle == false)
                        {
                            Console.WriteLine("Service is running, please close it!!");
                            return false;
                        }

                    }
                    catch (AbandonedMutexException)
                    {
                        // Log the fact the mutex was abandoned in another process, it will still get acquired
                        //Logger.ReportWarning("Previous instance of service ended abnormally...");
                    }

                    Kernel.Init(KernelLoadDirective.LoadServicePlugins);
                    _config = Kernel.Instance.ServiceConfigData;
                    //in case we crashed during a re-build...
                    _config.ForceRebuildInProgress = false;
                    _config.Save();

                    Plugin plugin = new Plugin();
                    plugin.Init(Kernel.Instance);

                    retval = true;
                }
                catch (Exception ex) {
                    Console.WriteLine("Error: ", ex.Message);
                }
            }
            return retval;
        }

        static void UpdateServiceProxy()
        {
            AppSettings.Initialise();
            string proxyLocation = @"""D:\Projects\mediabrowser-rc\MBWebService\MBWebService.Core\Client\MBServiceProxy.cs""";
            string commandArgs = string.Format(@"""C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcUtil.exe"" {0} /out:{1} /namespace:""*, MBWebService.Server.Proxy""", AppSettings.LocalPublisherUri, proxyLocation);

            ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", @"/c " + commandArgs);
            processStartInfo.RedirectStandardOutput = true;
            processStartInfo.UseShellExecute = false;
            processStartInfo.CreateNoWindow = true;

            Process process = new Process();
            process.StartInfo = processStartInfo;
            process.Start();

            string result = process.StandardOutput.ReadToEnd();
            Console.WriteLine(result);

            var kernel = MediaBrowser.Library.Kernel.Instance;
            Plugin plug = new Plugin();
            plug.Init(kernel);

            Console.WriteLine("Dual service started...");
        }

        static void InstallClient()
        {
            string commandArgs = @"""D:\Projects\mediabrowser-rc\MBWebService\MBWebService.Client\DevInstall.cmd"" /debug";
            ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", "/c" + commandArgs);
            processStartInfo.RedirectStandardOutput = true;
            processStartInfo.UseShellExecute = false;
            processStartInfo.CreateNoWindow = true;

            Process process = new Process();
            process.StartInfo = processStartInfo;
            process.Start();

            string result = process.StandardOutput.ReadToEnd();
            Console.WriteLine(result);
        }

        static void UninstallClient()
        {
            string commandArgs = @"""D:\Projects\mediabrowser-rc\MBWebService\MBWebService.Client\UninstallFromAssembly.cmd"" /debug";
            ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd", "/c" + commandArgs);
            processStartInfo.RedirectStandardOutput = true;
            processStartInfo.UseShellExecute = false;
            processStartInfo.CreateNoWindow = true;

            Process process = new Process();
            process.StartInfo = processStartInfo;
            process.Start();

            string result = process.StandardOutput.ReadToEnd();
            Console.WriteLine(result);
        }

        static void AttachToService(RemoteDevice serverName, MBWebService.Server.Proxy.PlaybackDevice device)
        {
            try
            {
                EndpointAddress address = new EndpointAddress(AppSettings.PublisherUri(serverName));
                InstanceContext context = new InstanceContext(new MediaBrowserClient());
                WSDualHttpBinding binding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
                //binding.Security = new WSDualHttpSecurity();
                binding.Security.Mode = WSDualHttpSecurityMode.None;
                MBWebService.Server.Proxy.MediaBrowserServerClient client = new MBWebService.Server.Proxy.MediaBrowserServerClient(context, binding, address);
                client.Subscribe(device);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogMessage("Error connecting to service: {0}", ex.Message);
            }
        }
    }
}
